#include <QDebug>
#include <opencv2/opencv.hpp>
#include <vector>
#include <QThread>
#include <QImage>

extern "C"{
#include "libavutil/avstring.h"
#include "libavutil/channel_layout.h"
#include "libavutil/eval.h"
#include "libavutil/mathematics.h"
#include "libavutil/pixdesc.h"
#include "libavutil/imgutils.h"
#include "libavutil/dict.h"
#include "libavutil/fifo.h"
#include "libavutil/parseutils.h"
#include "libavutil/samplefmt.h"
#include "libavutil/time.h"
#include "libavutil/bprint.h"
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include "libavfilter/avfilter.h"
#include "libavdevice/avdevice.h"
#include "libswscale/swscale.h"
#include "libavutil/opt.h"
#include "libavcodec/avfft.h"
#include "libswresample/swresample.h"
}

using namespace std;
using namespace cv;

bool is_load = false;
cv::CascadeClassifier faceDetector;
cv::Mat QImageToMat(const QImage &image)
{
    cv::Mat mat;
    switch(image.format())
    {
    case QImage::Format_ARGB32:
    case QImage::Format_RGB32:
    case QImage::Format_ARGB32_Premultiplied:
        mat = cv::Mat(image.height(), image.width(), CV_8UC4, (void*)image.constBits(), image.bytesPerLine());
        break;
    case QImage::Format_RGB888:
        mat = cv::Mat(image.height(), image.width(), CV_8UC3, (void*)image.constBits(), image.bytesPerLine());
        cv::cvtColor(mat, mat, cv::COLOR_RGB2BGR);
        break;
    case QImage::Format_Grayscale8:
        mat = cv::Mat(image.height(), image.width(), CV_8UC1, (void*)image.constBits(), image.bytesPerLine());
        break;
    default:
        qWarning("QImageToMat: Unsupported QImage format");
        return cv::Mat();
    }
    return mat.clone(); // 返回克隆，确保OpenCV的Mat和QImage不共享内存
}

cv::Mat AVFrameToCvMat(AVFrame* input_avframe, int format)
{
    int image_width = input_avframe->width;
    int image_height = input_avframe->height;

    cv::Mat resMat(image_height, image_width, CV_8UC3);
    int cvLinesizes[1];
    cvLinesizes[0] = resMat.step1();

    SwsContext* avFrameToOpenCVBGRSwsContext = sws_getContext(
        image_width,
        image_height,
        //AVPixelFormat::AV_PIX_FMT_YUV420P,
        (AVPixelFormat)format,
        image_width,
        image_height,
        AVPixelFormat::AV_PIX_FMT_BGR24,
        SWS_FAST_BILINEAR,
        nullptr, nullptr, nullptr
        );

    sws_scale(avFrameToOpenCVBGRSwsContext,
              input_avframe->data,
              input_avframe->linesize,
              0,
              image_height,
              &resMat.data,
              cvLinesizes);

    if (avFrameToOpenCVBGRSwsContext != nullptr)
    {
        sws_freeContext(avFrameToOpenCVBGRSwsContext);
        avFrameToOpenCVBGRSwsContext = nullptr;
    }

    return resMat;
}

void CvMatToAVFrame(const cv::Mat& input_mat, AVFrame* out_avframe)
{
    int image_width = input_mat.cols;
    int image_height = input_mat.rows;
    int cvLinesizes[1];
    cvLinesizes[0] = input_mat.step1();

    out_avframe->width = image_width;
    out_avframe->height = image_height;
    out_avframe->format = AV_PIX_FMT_YUV420P;

    SwsContext* openCVBGRToAVFrameSwsContext = sws_getContext(
        image_width,
        image_height,
        AVPixelFormat::AV_PIX_FMT_BGR24,
        image_width,
        image_height,
        AVPixelFormat::AV_PIX_FMT_YUV420P,
        SWS_FAST_BILINEAR,
        nullptr, nullptr, nullptr
        );

    sws_scale(openCVBGRToAVFrameSwsContext,
              &input_mat.data,
              cvLinesizes,
              0,
              image_height,
              out_avframe->data,
              out_avframe->linesize);

    if (openCVBGRToAVFrameSwsContext != nullptr)
    {
        sws_freeContext(openCVBGRToAVFrameSwsContext);
        openCVBGRToAVFrameSwsContext = nullptr;
    }
}

void faceRecongize(cv::CascadeClassifier faceCascade/*, cv::CascadeClassifier eyesCascade, cv::CascadeClassifier mouthCascade, */, cv::Mat frame)
{
    Mat gray;
    cv::cvtColor(frame, gray, cv::COLOR_BGR2GRAY);
    std::vector<cv::Rect> faces;
    if(frame.empty())
        return ;

    // 检测人脸
    faceCascade.detectMultiScale(gray, faces, 1.1, 2, 0 | cv::CASCADE_SCALE_IMAGE, cv::Size(30, 30));
    for (int i = 0; i < faces.size(); i++) {

        // 用椭圆画出人脸部分
        cv::Point center(faces[i].x + faces[i].width / 2, faces[i].y + faces[i].height / 2);
        ellipse(frame, center, cv::Size(faces[i].width / 2, faces[i].height / 2), 0, 0, 360, cv::Scalar(255, 0, 255), 4, 8, 0);
#if 0
        cv::Mat faceROI = frame(faces[i]);
        std::vector<cv::Rect> eyes;

        // 检测眼睛
        eyesCascade.detectMultiScale(faceROI, eyes, 1.1, 2, 0 | cv::CASCADE_SCALE_IMAGE, cv::Size(30, 30));
        for (int j = 0; j < eyes.size(); j++)
        {
            // 用圆画出眼睛部分
            cv::Point eye_center(faces[i].x + eyes[j].x + eyes[j].width / 2, faces[i].y + eyes[j].y + eyes[j].height / 2);
            int radius = cvRound((eyes[j].width + eyes[j].height)*0.25);
            circle(frame, eye_center, radius, cv::Scalar(255, 0, 0), 4, 8, 0);
        }

        cv::Mat mouthROI = frame(faces[i]);
        std::vector<cv::Rect> mouth;

        // 检测嘴部
        mouthCascade.detectMultiScale(mouthROI, mouth, 1.1, 2, 0 | cv::CASCADE_SCALE_IMAGE, cv::Size(30, 30));
        for (int k = 0; k < mouth.size(); k++)
        {
            //用长方形画出嘴部
            cv::Rect rect(faces[i].x + mouth[k].x, faces[i].y + mouth[k].y, mouth[k].width, mouth[k].height);
            rectangle(frame, rect, cv::Scalar(0, 255, 0), 2, 8, 0);
        }

        // 检测到两个眼睛和一个嘴巴, 可认为检测到有效人脸
        if (eyes.size() >= 2 && mouth.size() >= 1) {

            // 人脸上方区域写字进行标识
            cv::Point centerText(faces[i].x + faces[i].width / 2 - 40, faces[i].y - 20);
            cv::putText(frame, "face", centerText, cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(0, 0, 255), 2);
        }
#endif

    }
}

AVFrame* CVMat_to_AVFrame(cv::Mat& inMat)
{
    //得到Mat信息
    AVPixelFormat dstFormat = AV_PIX_FMT_YUV420P;
    int width = inMat.cols;
    int height = inMat.rows;

    //创建AVFrame填充参数 注：调用者释放该frame
    AVFrame* frame = av_frame_alloc();
    frame->width = width;
    frame->height = height;
    frame->format = dstFormat;

    //初始化AVFrame内部空间
    int ret = av_frame_get_buffer(frame, 0);
    if (ret < 0)
    {
        std::cerr << "Could not allocate the video frame data";
        return nullptr;
    }

    ret = av_frame_make_writable(frame);
    if (ret < 0)
    {
        std::cerr << "Av frame make writable failed.";
        return nullptr;
    }

    cv::Size osize = inMat.size();
    //转换颜色空间为YUV420
    cv::cvtColor(inMat, inMat, cv::COLOR_BGR2YUV_I420);
    cv::Size nsize = inMat.size();

    // 按YUV420格式，设置数据地址，注意内存对齐
    int frame_width = frame->linesize[0];
    int frame_size = width * height;
    unsigned char* data = inMat.data;
    // 无填充情况
    if (frame_width == width) {
        memcpy(frame->data[0], data, frame_size);
        memcpy(frame->data[1], data + frame_size, frame_size / 4);
        memcpy(frame->data[2], data + frame_size * 5 / 4, frame_size / 4);
    }
    else {
        memset(frame->data[0], 0, frame->linesize[0] * height);
        memset(frame->data[1], 0, frame->linesize[0] * height / 4);
        memset(frame->data[2], 0, frame->linesize[0] * height / 4);
        // Y Panel
        for (int i = 0; i < height; i++) {
            memcpy(frame->data[0] + i * frame->linesize[0], data + i * width, width);
        }
        unsigned char* udata = data + frame_size;
        unsigned char* vdata = udata + frame_size / 4;
        // UV Panel
        for (int i = 0; i < height / 2; i++) {
            memcpy(frame->data[1] + i * frame->linesize[1], udata + i * width / 2, width / 2);
            memcpy(frame->data[2] + i * frame->linesize[2], vdata + i * width / 2, width / 2);
        }
    }

    return frame;
}

QImage matToQImage(const cv::Mat &mat)
{
    QImage image;
    switch(mat.type())
    {
    case CV_8UC1:
        // QImage构造：数据，宽度，高度，每行多少字节，存储结构
        image = QImage((const unsigned char*)mat.data, mat.cols, mat.rows, mat.step, QImage::Format_Grayscale8);
        break;
    case CV_8UC3:
        image = QImage((const unsigned char*)mat.data, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
        image = image.rgbSwapped(); // BRG转为RGB
        // Qt5.14增加了Format_BGR888
        // image = QImage((const unsigned char*)mat.data, mat.cols, mat.rows, mat.cols * 3, QImage::Format_BGR888);
        break;
    case CV_8UC4:
        image = QImage((const unsigned char*)mat.data, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32);
        break;
    case CV_16UC4:
        image = QImage((const unsigned char*)mat.data, mat.cols, mat.rows, mat.step, QImage::Format_RGBA64);
        image = image.rgbSwapped(); // BRG转为RGB
        break;
    default:
        break;
    }
    return image;
}

QImage pic_handle(AVFrame* img, int format)
{

    if(is_load == false){
        if(faceDetector.load("haarcascade_frontalface_default.xml") == false){
            qDebug() << "load xml failed"<< endl;
      //      return NULL;
        }
          is_load = true;
    }

    Mat bgr = AVFrameToCvMat(img, format);
    faceRecongize(faceDetector, bgr);

    cv::cvtColor(bgr, bgr, cv::COLOR_BGR2RGB);
    QImage qtImage(bgr.data, bgr.cols, bgr.rows, bgr.step, QImage::Format_RGB888);

    return qtImage.copy();
}

QImage add_mask(QImage img, QString mask, int x, int y)
{
    Mat bgr = cv::Mat(img.height(), img.width(), CV_8UC3, img.bits(), img.bytesPerLine());
    cv::cvtColor(bgr, bgr, cv::COLOR_RGB2BGR);

    // 设置水印文本信息
    string watermarkText = mask.toStdString();

    // 设置文本参数（字体、位置、大小等）
    int fontFace = FONT_HERSHEY_SIMPLEX;
    double fontScale = 1.5;
    int thickness = 2;
    int baseline = 0;
    Size textSize = getTextSize(watermarkText, fontFace, fontScale, thickness, &baseline);
    // 计算文本位置（居中）
    Point textOrg(x, y+textSize.height);
    // 绘制文字水印到副本图像上
    putText(bgr, watermarkText, textOrg, fontFace, fontScale, Scalar(255, 255, 255), thickness);
    cv::cvtColor(bgr, bgr, cv::COLOR_BGR2RGB);
    QImage qtImage (bgr.data, bgr.cols, bgr.rows, bgr.step, QImage::Format_RGB888);
    return qtImage.copy();

}

QImage set_transform(QImage img, int x, int y)
{

    Mat bgr = cv::Mat(img.height(), img.width(), CV_8UC3, img.bits(), img.bytesPerLine());
    cv::cvtColor(bgr, bgr, cv::COLOR_RGB2BGR);
    Mat canvas = Mat::zeros(bgr.size(), bgr.type()); //画布，重新生成哈哈图像

    //图像中心
    int cx = bgr.cols / 2;
    int cy = bgr.rows / 2;
    //决定哈哈镜大小
    int radius = 50;

    //图像像素修改
    for (int i = 0; i < bgr.rows; i++)
    {
        for (int j = 0; j < bgr.cols; j++)
        {
            //任意像素点到图像中心距离
            int dx = j - cx;
            int dy = i - cy;
            //重新映射像素点位置
            int x = (dx / 2)*(sqrt(pow(dx, 2) + pow(dy, 2)) / radius) + cx;
            int y = (dy / 2)*(sqrt(pow(dx, 2) + pow(dy, 2)) / radius) + cy;

            for (int c = 0; c < 3; c++)
            {
                //防止越界
                if ((x > 0 && x < bgr.cols) && (y > 0 && y < bgr.rows))
                {
                    canvas.at<Vec3b>(i, j)[c] = bgr.at<Vec3b>(y, x)[c];
                }
            }
        }
    }
    cv::cvtColor(canvas, canvas, cv::COLOR_BGR2RGB);
    QImage qtImage (canvas.data, canvas.cols, canvas.rows, canvas.step, QImage::Format_RGB888);
    return qtImage.copy();

}

QImage set_cv_mosic(QImage qimage, int x, int y, int width, int height)
{
    Mat bgr = cv::Mat(qimage.height(), qimage.width(), CV_8UC3, qimage.bits(), qimage.bytesPerLine());
    cv::cvtColor(bgr, bgr, cv::COLOR_RGB2BGR);

    int step = 10;//步长

    //仅对人脸区域进行像素修改。遍历人脸矩形框区域像素，并对其进行修改
    for (int i = y; i < (y + height); i += step)
    {
        for (int j = x; j < (x + width); j += step)
        {
            //将人脸矩形框再细分为若干个小方块，依次对每个方块修改像素（相同方块赋予相同灰度值）
            for (int k = i; k < (step + i); k++)
            {
                for (int m = j; m < (step + j); m++)
                {
                    //对矩形区域像素值进行修改，rgb三通道
                    for (int c = 0; c < 3; c++)
                    {
                        bgr.at<Vec3b>(k, m)[c] = bgr.at<Vec3b>(i, j)[c];
                    }
                }
            }
        }
    }

    cv::cvtColor(bgr, bgr, cv::COLOR_BGR2RGB);
    QImage qtImage (bgr.data, bgr.cols, bgr.rows, bgr.step, QImage::Format_RGB888);
    return qtImage.copy();
}

QImage carNo(QImage src)
{
    Mat img = cv::Mat(src.height(), src.width(), CV_8UC3, src.bits(), src.bytesPerLine());
    cv::cvtColor(img, img, cv::COLOR_RGB2BGR);
    //高斯模糊
    Mat Gauss_img;
    GaussianBlur(img, Gauss_img, Size(3, 3), 0, 0, BORDER_DEFAULT);
    //imshow("2.gauss",Gauss_img);
    //转化灰度图
    Mat gray_img;
    cvtColor(Gauss_img, gray_img, COLOR_BGR2GRAY);
    //imshow("3.gray",gray_img);
    //Sobel算子
    Mat Sobel_x, absX;
    Sobel(gray_img, Sobel_x, CV_16S, 1, 0);
    convertScaleAbs(Sobel_x, absX);
    //imshow("4.Abs",absX);
    //二值化
    Mat thr_img;
    threshold(absX, thr_img, 0, 255, THRESH_OTSU);
    //imshow("5.threshold",thr_img);

    //闭操作
    Mat element, mor_img;
    element = getStructuringElement(MORPH_RECT, Size(17, 5));
    morphologyEx(thr_img, mor_img, MORPH_CLOSE, element);
    //imshow("6.morphologyEx",mor_img);

    //膨胀、腐蚀
    Mat kernelX, kernelY, ker_img;
    kernelX = getStructuringElement(MORPH_RECT, Size(20, 1));
    kernelY = getStructuringElement(MORPH_RECT, Size(1, 19));

    dilate(mor_img, ker_img, kernelX);
    erode(ker_img, ker_img, kernelX);

    erode(ker_img, ker_img, kernelY);
    dilate(ker_img, ker_img, kernelY);
    //imshow("7.dilate and erode",ker_img);

    //中值滤波
    Mat med_img;
    medianBlur(ker_img, med_img, 15);
    //imshow("8.medianBlur",med_img);

    //查找轮廓
    vector<vector<Point>>contours;
    findContours(med_img, contours, RETR_TREE, CHAIN_APPROX_SIMPLE);
    //drawContours(img,contours,-1, Scalar(0, 0, 255), 3);
    //imshow("9.result",img);

    //ROI提取
    Mat roi_img;
    vector<Rect> boundRect(contours.size());
    for (int i = 0; i < contours.size(); i++)
    {
        boundRect[i] = boundingRect(contours[i]);
        if (boundRect[i].width > boundRect[i].height * 2) //车牌尺寸判断
        {
            //在原图上绘制矩形
            rectangle(img, Rect(boundRect[i].x, boundRect[i].y, boundRect[i].width, boundRect[i].height), Scalar(0, 255, 0), 2);
            //ROI提取
            roi_img = img(Rect(boundRect[i].x, boundRect[i].y, boundRect[i].width, boundRect[i].height));
        }
    }

    cv::cvtColor(img, img, cv::COLOR_BGR2RGB);
    QImage qtImage (img.data, img.cols, img.rows, img.step, QImage::Format_RGB888);
    return qtImage.copy();
}
